/**
 * WangSong 2009-10-18	Select查询也支持返回SQL,但分页模式除外
 */
package cn.biplam.common.interfaces;

import java.util.ArrayList;

import cn.biplam.common.bean.sqlengine.Sql;
import cn.biplam.common.client.DataFilter;
import cn.biplam.common.client.Database;
import cn.biplam.common.client.DbResource;
import cn.biplam.common.client.Operator;
import cn.biplam.common.client.OperatorResult;
import cn.biplam.common.client.Paging;
import cn.biplam.common.client.Sequence;
import cn.biplam.common.tools.TOOLS;
import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.common.wrapper.sqlresult.SqlResult;

/**
 * 数据操作类基础类
 * @author XiaoRuxing 2009-5-19上午11:17:51
 * @version 1.0
 */
public abstract class DataOperator {

	/** 操作ID  */
	protected String opId;
	/** 用户ID */
	protected String userId;
	/** 操作过滤器 */
	protected DataFilter filter;
	/** 数据源 */
	protected DbResource dbResource;
	/** 操作结果 */
	protected OperatorResult result;
	/** 数据操作类对应表名 */
	protected String tableName;
	/** 数据操作类对应表主键 */
	protected String mainKey;
	/** 字段排序主键*/
	protected String orderKey;

	/** 是否分页模式查询数据 
	 * 在filter中约定用queryModel参数来判断是否分页
	 * 如果获取到queryModel是page则为分页模式 
	 * */
	private boolean pageModel = false;

	/**
	 * 操作类型 
	 */
	public enum Operator_Type{
		Select,
		DML
	}

	public DataOperator() throws ErrorMessage{
		this("");
	};

	/**
	 * 构造方法  传入表名称构造,表名称不允许为空
	 * @param tableName
	 * @throws ErrorMessage
	 */
	public DataOperator(String tableName) throws ErrorMessage{
		this.result=new OperatorResult();
		this.tableName=tableName;
	}

	/**
	 * 根据表名和用户ID,生成记录ID
	 * @return 记录ID
	 * @throws ErrorMessage 
	 */
	public String generatorRowID() throws ErrorMessage{
		String rowID = Sequence.getSequence(userId); 
		this.result.setLastRowId(rowID);
		return rowID;	
	}

	/**
	 * 获取数据处理Sql列表，然后执行获取到得Sql列表
	 * @param operatorType 操作类型 
	 * @param params       参数列表
	 * @param act          执行操作类型自定义指示符
	 * @return             数据处理Sql列表
	 * @throws ErrorMessage 
	 */
	protected OperatorResult doing(ArrayList<String> sql,Operator_Type type) throws ErrorMessage{
		Database database=new Database(this.dbResource,userId,opId);
		switch(type){
		case Select:
			if(this.pageModel){
				if(filter.isIfGetSql()){	//仅返回SQL
					throw new ErrorMessage("Page mode can not return sql! ");
				}
				return this.doing(sql);
			}else{
				if(filter.isIfGetSql()){	//仅返回SQL
					setSqls(result,sql);
				}else{
					if(sql.size()>0){
						if(filter==null || filter.getValue(Operator.lineLimit)==null ||
								"".equals(filter.getValue(Operator.lineLimit))){
							result.setSelectResult(database.executeSelect(new Sql(sql.get(0))));
						}else{
							result.setSelectResult(database.executeSelectLimit(new Sql(sql.get(0)),
									TOOLS.stringToInt(filter.getValue(Operator.lineLimit))));
						}
					}
				}
				return result;
			}
		case DML:
			sql = getSqlsFromFilter(sql);
			if(filter.isIfGetSql()){
				setSqls(result, sql);
			}else if(sql.size()>0){
				result.setDmlResult(database.executeDMLBatch(sql));
			}
			return result;
		default:
			return null;
		}
	}

	/**
	 * 设置外部传来的sql
	 * @param sql
	 */
	private ArrayList<String> getSqlsFromFilter(ArrayList<String> sql){
		if(filter.getSqls()!=null && filter.getSqls().size()>0){
			return filter.getSqls();
		}
		return sql;
	}

	/**
	 * 设置返回sql，但不执行sql
	 */
	private void setSqls(OperatorResult result,ArrayList<String> sql){
		result.setSqls(sql);
	}

	private void _setMainKey(){
		if(this.mainKey!=null){
			this.result.setMainKey(this.mainKey);
		}
	}

	/**
	 * 数据操作类交换器，根据传入的交换码调用交换码对应的方法
	 * @param opId        交换码
	 * @param userId      用户ID
	 * @param filter      操作过滤器
	 * @param dbResource  数据源
	 * @return 交换码对应操作的结果
	 * @throws ErrorMessage
	 */
	public OperatorResult get(String opId, String userId,
			DataFilter filter, DbResource dbResource) throws ErrorMessage{
		if(filter==null){
			throw new ErrorMessage("DataFilter is null.");
		}
		this.opId=opId;
		this.userId=userId;
		this.filter=filter;
		this.dbResource=dbResource;
		_setQueryModel();
		_setMainKey();
		return _exchange();
	}

	/**
	 * 在filter中约定用queryModel参数来判断是否分页
	 * 如果获取到queryModel是page则为分页模式 
	 */
	private void _setQueryModel(){
		if(filter!=null){
			String model = filter.getValue(".queryModel");
			if("page".equals(model)){
				this.pageModel = true;
			} 
		}
	}

	/**
	 * 实现类的交换器，根据交换代码执行相应的方法生成并执行SQL语句，返回执行结果
	 * @return 交换代码对应Sql的执行结果
	 * @throws ErrorMessage
	 */
	protected abstract OperatorResult _exchange() throws ErrorMessage;

	/**
	 * 获取数据处理Sql列表，然后执行获取到得Sql列表
	 * @param sql 数据处理Sql列表
	 * @param pageNum 页码 
	 * @param orderName 排序字段名称  
	 * @return OperatorResult            
	 * @throws ErrorMessage 
	 */
	protected OperatorResult doing(ArrayList<String> sql) throws ErrorMessage{

		Database database=new Database(dbResource,userId,opId);
		if(sql.size()>0){
			/** 设置分页信息 (总页数、总行数、是否有上一页、是否有下一页)*/
			//处理sql ，取总页数信息
			Paging page = new Paging(this.filter.getValue("showPageLine"));
			SqlResult rs = database.executeSelect(new Sql(page.getSqlTotle(sql.get(0))));
			result.setPaging(
					rs, //当前总页数信息
					this.filter.getValue("showPageLine"),
					userId,
					opId+this.filter.getKeyCode()//当前记录集唯一ID
			);
			/** 设置当页信息  */
			Paging curr = result.getPaging();
			SqlResult sqlStr = page.getSqlPartByDb(
					sql.get(0),
					database,
					dbResource,
					userId,
					opId+this.filter.getKeyCode(),
					curr);
			result.setSelectResult(sqlStr);
		}
		return result;
	}
}